#include "lcd.h"
#include "camera.h"

int redoffset = 2;
int greenoffset=1;
int blueoffset=0;

extern int *lcd_ptr; //屏幕映射后的内存首地址

int R[256][256];
int G[256][256][256];
int B[256][256];

uint8_t *gyuv = NULL;
//显示摄像头采集到的画面
void display(uint8_t *yuv)
{
	int R0, G0, B0;
	int R1, G1, B1;	

	uint8_t Y0, U;
	uint8_t Y1, V;

	int w = CAMERA_W;
	int h = CAMERA_H;

	uint8_t *fbtmp = (uint8_t *)lcd_ptr;
	int yuv_offset, lcd_offset;
	for(int y=0; y<h; y++)
	{
		for(int x=0; x<w; x+=2)
		{
			yuv_offset = ( CAMERA_W*y + x ) * 2;
			lcd_offset = ( 800*y + x ) * 4;
			
			Y0 = *(yuv + yuv_offset + 0);
			U  = *(yuv + yuv_offset + 1);
			Y1 = *(yuv + yuv_offset + 2);
			V  = *(yuv + yuv_offset + 3);

			*(fbtmp + lcd_offset + redoffset  +0) = R[Y0][V];
			*(fbtmp + lcd_offset + greenoffset+0) = G[Y0][U][V];
			*(fbtmp + lcd_offset + blueoffset +0) = B[Y0][U];
			*(fbtmp + lcd_offset + redoffset  +4) = R[Y1][V];
			*(fbtmp + lcd_offset + greenoffset+4) = G[Y1][U][V];
			*(fbtmp + lcd_offset + blueoffset +4) = B[Y1][U];
		}
	}

}

//线程函数：进行车牌识别
void *LPR(void* arg)
{
	sleep(1);
	while (1)
	{
		//将摄像头当前显示的画面的yuv数据转换成一个jpg图片
		yuv2jpg(gyuv);
		//printf("获取图片并保存成功!\n");
		//去识别图像中的车牌
    	//将识别的结果重定向到一个文件(test.txt)中去
    	//方便后续代码对这个数据进行分析
    	system("./alpr ./a.jpg > test.txt");
		//将识别到的车牌信息读取出来
		int fd_tex = open("./test.txt",O_RDWR);
		if (fd_tex == -1)
		{
			continue;
		}
		char buf[1024] = {0};
		read(fd_tex,buf,1024);
		printf("%s",buf);
		//根据buf中的数据来判断是否识别成功
		int x1 = buf[27] - '0';//成功率100%
		int x2 = buf[29] - '0' ;//成功率大于90%
		//如果识别成功了
        if(strlen(buf) > 40  && (x2 == 9 || x1 == 1))
		{
			//touch 一下，再把车牌显示到开发板
			int ret = touch();
			if(ret)
			{
				int x0 = 400;
				int y0 = 120;
				int color = 0xff;//
				int w = 8;
				int h = 16;
				display_license_plate( x0, y0, color,buf + 17, w, h);//显示车牌号
				
				int color_wel = 0xff0000;
				int y_wel = 136;
				int w_wel = 16;
				display_welcome(x0,y_wel,color_wel,w_wel,h);//显示欢迎回家
				
				char* pathname = "/course/smile";
	            int x1 = x0 + 80;
	            lcd_display_jpeg(pathname, x1, y_wel);
			}
		}
		
		else if(strlen(buf) > 40  && x2 != 9 && x1 != 1)
		{
			printf("识别成功率低\n");
		}
		close(fd_tex);
	}
}

void start(int camfd,int nbuf)
{
	// 定义相应数量的struct v4l2_buffer
	// 每一个struct v4l2_buffer对应内核摄像头驱动中的一个缓存
	struct v4l2_buffer buffer[nbuf];
	int length[nbuf];
	uint8_t *start[nbuf];

	for(int i=0; i<nbuf; i++)
	{
		bzero(&buffer[i], sizeof(buffer[i]));
		buffer[i].type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
		buffer[i].memory = V4L2_MEMORY_MMAP;
		buffer[i].index = i;
		ioctl(camfd, VIDIOC_QUERYBUF, &buffer[i]);
		length[i] = buffer[i].length;
		start[i] = mmap(NULL, buffer[i].length,	PROT_READ | PROT_WRITE,
				        MAP_SHARED,	camfd, buffer[i].m.offset);

		ioctl(camfd , VIDIOC_QBUF, &buffer[i]);
	}

	//启动摄像头数据采集
	enum v4l2_buf_type vtype= V4L2_BUF_TYPE_VIDEO_CAPTURE;
	ioctl(camfd, VIDIOC_STREAMON, &vtype);

	struct v4l2_buffer v4lbuf;
	bzero(&v4lbuf, sizeof(v4lbuf));
	v4lbuf.type  = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	v4lbuf.memory= V4L2_MEMORY_MMAP;
	
	// 开始抓取摄像头数据并在屏幕播放视频
	int i=0;
	while(1)
	{
		// 从队列中取出填满数据的缓存
		v4lbuf.index = i%nbuf;
		ioctl(camfd , VIDIOC_DQBUF, &v4lbuf);
		//显示摄像头采集到的画面
		display(start[i%nbuf]);
		gyuv = start[i%nbuf];
	 	// 将已经读取过数据的缓存块重新置入队列中 
		v4lbuf.index = i%nbuf;
		ioctl(camfd , VIDIOC_QBUF, &v4lbuf);
		i++;
	}
}

int main()
{
	//初始化显示屏
	lcd_init();
    
	//改变全屏颜色
	int color_back = 0xffffff;
	lcd_display_FullScreen(color_back);
	
	//准备好YUV---->RGB映射表
	convert();
	
	//初始化摄像头
	int nbuf = 3;//缓冲区中暂存3帧图片数据
	int camfd = camera_init("/dev/video7",nbuf);

	//创建一个线程去识别当前画面中的车牌
	pthread_t thread_id;
    int res = pthread_create(&thread_id, NULL,LPR, NULL);
    if (res)
    {
        printf("create thread error!\n");
        return -1;
    }
	
	//启动摄像头，获取图像数据并显示
	start(camfd,nbuf);

	lcd_close();
	return 0;
}

